package org.openkanban.server.dao.impl;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import org.openkanban.server.dao.BoardDao;
import org.openkanban.server.domain.Activity;
import org.openkanban.server.domain.Board;
import org.openkanban.server.domain.User;
import org.openkanban.shared.util.StatusCodes;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

/**
 * jpa implementation of board data access object
 */
@Repository
public class BoardDaoJpaImpl implements BoardDao {

    @PersistenceContext
    private EntityManager entityManager;

    @Override
    @Transactional
    public Board createBoard(Board board, Long userId) {
	User user = entityManager.find(User.class, userId);
	board.getBoardUser().add(user);
	entityManager.persist(board);
	return board;
    }

    @Override
    public Board getBoardById(Long boardId) {
	Board board = entityManager.find(Board.class, boardId);
	return board;
    }

    @Override
    public Board getBoardByActivityId(Long parentActivityId) {
	Query query = entityManager.createQuery("SELECT b from Board b JOIN b.activities a WHERE a.activityId=:activityId");
	query.setParameter("activityId", parentActivityId);
	@SuppressWarnings("unchecked")
	List<Board> boardResultList = query.getResultList();
	if (boardResultList.isEmpty()) {
	    return new Board();
	}
	return boardResultList.iterator().next();
    }

    @Override
    public List<Board> getAll() {
	Query query = entityManager.createQuery("SELECT b FROM Board b");
	@SuppressWarnings("unchecked")
	List<Board> boardList = (List<Board>) query.getResultList();
	return boardList;
    }

    @Override
    @Transactional
    public Board removeBoard(Board board) {
	entityManager.remove(board);
	return board;
    }

    @Override
    @Transactional
    public Activity addActivityToBoard(Long parentBoardId, Activity newActivity) {
	Board board = entityManager.find(Board.class, parentBoardId);
	if (board != null) {
	    entityManager.persist(newActivity);
	    board.getActivities().add(newActivity);
	    entityManager.merge(board);
	    return newActivity;
	}
	return null;
    }

    @Override
    @Transactional
    public Activity removeFromBoard(Long parentBoardId, Activity newActivity) {
	Board board = entityManager.find(Board.class, parentBoardId);
	board.getActivities().remove(newActivity);
	entityManager.merge(board);
	return newActivity;
    }

    @Override
    @Transactional
    public Board updateBoard(Board board) {
	Board boardToUpdate = entityManager.find(Board.class, board.getBoardId());
	boardToUpdate.setBoardName(board.getBoardName());
	return boardToUpdate;
    }

    @Override
    @Transactional
    public StatusCodes addContactToBoard(Long parentBoardId, User newUser) {
	Board board = entityManager.find(Board.class, parentBoardId);
	if (board != null) {
	    board.getBoardUser().add(newUser);
	    entityManager.merge(board);
	    return StatusCodes.OK;
	}
	return StatusCodes.DATABASE_ERROR;
    }

    @Override
    @Transactional
    public StatusCodes removeContactFromBoard(Long parentBoardId, Long userId) {
	User userToRemove = entityManager.find(User.class, userId);
	Board board = entityManager.find(Board.class, parentBoardId);
	if (board != null) {
	    board.getBoardUser().remove(userToRemove);
	    entityManager.merge(board);
	    return StatusCodes.OK;
	}
	return StatusCodes.DATABASE_ERROR;
    }

    @Override
    public Board getDefaultBoardByUserId(Long userId) {
	Query query = entityManager.createQuery("SELECT b FROM Board b JOIN b.boardUser u WHERE u.userId=:userId ORDER BY b.boardId");
	query.setParameter("userId", userId);
	query.setMaxResults(1);

	@SuppressWarnings("unchecked")
	List<Board> boardList = query.getResultList();

	if (boardList.size() != 1) {
	    return null;
	}

	return (Board) boardList.iterator().next();
    }

    @Override
    public Long getNextBoardId(Long currentBoardId, Long userId) {
	Query query = entityManager
		.createQuery("SELECT b.boardId FROM Board b JOIN b.boardUser u WHERE u.userId=:userId AND b.boardId>:currentBoardId ORDER BY b.boardId");
	query.setParameter("currentBoardId", currentBoardId);
	query.setParameter("userId", userId);
	query.setMaxResults(1);

	@SuppressWarnings("unchecked")
	List<Long> boardIdList = query.getResultList();
	if (boardIdList.size() != 1) {
	    return null;
	}

	return (Long) boardIdList.iterator().next();
    }

    @Override
    public Long getPriorBoardId(Long currentBoardId, Long userId) {
	Query query = entityManager
		.createQuery("SELECT b.boardId FROM Board b JOIN b.boardUser u WHERE u.userId=:userId AND b.boardId<:currentBoardId ORDER BY b.boardId DESC");
	query.setParameter("currentBoardId", currentBoardId);
	query.setParameter("userId", userId);
	query.setMaxResults(1);

	@SuppressWarnings("unchecked")
	List<Long> boardIdList = query.getResultList();

	if (boardIdList.size() != 1) {
	    return null;
	}

	return (Long) boardIdList.iterator().next();
    }
}
